package es.efor.ics.gev.model;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

/**
 * The persistent class for the <b>CLASES</b> database table.
 * 
 * @author dlisbona
 * 
 */
@Entity
@Table(name = "CLASES")
public class Clase extends BaseObject implements Serializable {

	// static data
	private static final long serialVersionUID = 8202603522898586340L;

	// private instance data
	private Long id;
	private String denominacion;
	private Date fechaInicio;
	private Date fechaFin;
	private Integer horas;
	private Set<Material> materiales = new HashSet<Material>();
	private Aula aula;
	private String observacionesMaterial;
	private Integer version;

	/**
	 * Construct an uninitialized <code>Clase</code> (for runtime proxy
	 * generation in Hibernate).
	 */
	public Clase() {
	}

	// ********************** Accessor Methods ********************** //

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "CLASE_ID")
	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@Column(name = "DENOMINACION", length = 255, nullable = false)
	public String getDenominacion() {
		return denominacion;
	}

	public void setDenominacion(String denominacion) {
		this.denominacion = denominacion;
	}

	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "FECHA_INICIO", nullable = true)
	public Date getFechaInicio() {
		return fechaInicio;
	}

	public void setFechaInicio(Date fechaInicio) {
		this.fechaInicio = fechaInicio;
	}

	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "FECHA_FIN", nullable = true)
	public Date getFechaFin() {
		return fechaFin;
	}

	public void setFechaFin(Date fechaFin) {
		this.fechaFin = fechaFin;
	}

	@Column(name = "HORAS")
	public Integer getHoras() {
		return horas;
	}

	public void setHoras(Integer horas) {
		this.horas = horas;
	}
	
	@ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, fetch = FetchType.LAZY)
	@JoinTable(name = "CLASES_MATERIALES", joinColumns = @JoinColumn(name = "CLASE_ID"), inverseJoinColumns = @JoinColumn(name = "MATERIAL_ID"))
	@OrderBy("nombreMaterial")
	@org.hibernate.annotations.ForeignKey(name = "FK_CLA_MAT_CLASE_ID", inverseName = "FK_CLA_MAT_MATERIAL_ID")
	@org.hibernate.annotations.LazyCollection(value = org.hibernate.annotations.LazyCollectionOption.TRUE)
	@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.SAVE_UPDATE)
	public Set<Material> getMateriales() {
		return materiales;
	}

	public void setMateriales(Set<Material> materiales) {
		this.materiales = materiales;
	}
	
	public boolean addMaterial(Material material) {
		if (material == null) {
			throw new IllegalArgumentException("Null material!");
		}
		if (this.materiales.add(material)) {
			return material.getClases().add(this);
		}
		return false;
	}
	
	public boolean removeMaterial(Material material) {
		if (material == null) {
			throw new IllegalArgumentException("Null material!");
		}
		if (this.materiales.remove(material)) {
			return material.getClases().remove(this);
		}
		return false;
	}
	
	public void removeAllMateriales(boolean updateMaterial) {
		for (Material material : materiales) {
			if (updateMaterial) {
				material.getClases().remove(this);
			}
		}
		materiales.clear();
	}
	
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "CLASE_AULA_ID", referencedColumnName = "AULA_ID")
	@org.hibernate.annotations.ForeignKey(name = "FK_CLASE_AULA_ID")
	public Aula getAula() {
		return aula;
	}

	public void setAula(Aula aula) {
		this.aula = aula;
	}

	@Column(name = "OBSERVACIONES_MATERIAL", length = 255)
	public String getObservacionesMaterial() {
		return observacionesMaterial;
	}

	public void setObservacionesMaterial(String observacionesMaterial) {
		this.observacionesMaterial = observacionesMaterial;
	}

	@Version
	@Column(name = "OBJ_VERSION")
	public Integer getVersion() {
		return version;
	}

	public void setVersion(Integer version) {
		this.version = version;
	}

	// ********************** Common Methods ********************** //

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Clase == false) {
			return false;
		}
		if (this == obj) {
			return true;
		}
		Clase clase = (Clase) obj;
		return new EqualsBuilder().append(this.getDenominacion(),
				clase.getDenominacion()).isEquals();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder(17, 37).append(this.getDenominacion())
				.toHashCode();
	}

	@Override
	public String toString() {
		return new ToStringBuilder(this, ToStringStyle.DEFAULT_STYLE).append(
				"denominacion", this.getDenominacion()).toString();
	}

}
